/*
@ClassName PlanScheduleServiceImpl
@Description TODO
@Author SubUp
@Date   2022/8/1
@Version 1.0
*/

package com.sunjob.mrojobschedule.service.impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import com.sunjob.common.constant.MROConstant;
import com.sunjob.common.domain.loginServer.SysUser;
import com.sunjob.common.domain.scheduleServer.*;
import com.sunjob.common.domain.scheduleServer.orm.PlanResult;
import com.sunjob.common.exception.MROException;
import com.sunjob.common.mroAnno.MethodVerify;
import com.sunjob.common.result.Result;
import com.sunjob.common.util.MROUtils;
import com.sunjob.mrojobschedule.mapper.PlanScheduleMapper;
import com.sunjob.mrojobschedule.service.PlanScheduleService;
import com.sunjob.mrojobschedule.service.ProductScheduleService;
import com.sunjob.mrojobschedule.util.PageExample;
import com.sunjob.mrojobschedule.util.ScheduleUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/* 业务逻辑
* 待进一步完善 */
@Service
public class PlanScheduleServiceImpl implements PlanScheduleService {
    private static final Logger log = LoggerFactory.getLogger(PlanScheduleServiceImpl.class);
    @Resource
    private PlanScheduleMapper planScheduleMapper;
    @Resource
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductScheduleService productScheduleService;
    @Resource
    private PageExample pageExample;
    /**
     * @param pageId
     * @return 查询计划信息的原始数据
     */
    @Override
    @Transactional
    @MethodVerify
    public List<PlanSchedule> selectPlanList(String pageId) {
        List<PlanSchedule> plans = getPlansByRedis();
        Integer page = pageExample.checkPageId(ScheduleUtils.transferToInt(pageId));
        if(plans.size() != 0)
            return pageExample.getPages(plans,page);
        log.info("redis search failure ···"+plans);
        return pageExample.getPages(planScheduleMapper.queryAllPlan(),page);
    }

    /**
     * @param pageId
     * @return 返回 计划调度的计划信息
     */
    @Override
    @Transactional
    @MethodVerify
    public List selectPlanOrmList(String pageId) {
        List<PlanSchedule> plans = getPlansByRedis();
        Integer page = pageExample.checkPageId(ScheduleUtils.transferToInt(pageId));
        if(plans.size() != 0)
            return pageExample.getPages(conformityPlanParam(plans),page);
        log.info("redis search failure ···"+plans);
        return pageExample.getPages(planScheduleMapper.queryAllPlanResult(),page);
    }

    /**
     * 根据计划编号 查询管理数据
     * @param planId
     * @return
     */
    @Override
    @Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRES_NEW)
    @MethodVerify
    public List<PlanSchedule> selectPlanById(String planId) {
        List<PlanSchedule> planSchedules = getPlansByRedis();
        Long planNumber = ScheduleUtils.transferToLong(planId);
        List<PlanSchedule> planScheduleList = matchPlanId(planSchedules,planNumber);
        if(planScheduleList.size() == 1)
            return pageExample.getPages(conformityPlanParam(planScheduleList),1);
        log.info("redis search failure ···"+planScheduleList);
        return pageExample.getPages(planScheduleMapper.queryPlanById(planNumber),1);
    }

    @Override
    @Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRES_NEW)
    @MethodVerify
    public List<PlanResult> selectPlanOrmById(String planId) {
        List<PlanSchedule> planSchedules = getPlansByRedis();
        Long planNumber = ScheduleUtils.transferToLong(planId);
        List<PlanSchedule> planScheduleList =matchDimPlanId(planSchedules,planNumber);
        if(planScheduleList.size() != 0)
            return pageExample.getPages(conformityPlanParam(planScheduleList),1);
        log.info("redis search failure ···"+planScheduleList);
        return pageExample.getPages(planScheduleMapper.queryPlanOrmById(planNumber),1);
    }

    /**
     * @param examineObjName
     * @return 根据检修对象名，模糊查询计划调度管理数据
     */
    @Override
    @Transactional
    @MethodVerify
    public List<PlanResult> selectPlanResultByObjName(String examineObjName) {
        List<PlanSchedule> planSchedules = getPlansByRedis();
        List<PlanSchedule> planScheduleList = matchDimPlanByObjName(planSchedules,examineObjName);
        if(planScheduleList.size() != 0)
            return pageExample.getPages(conformityPlanParam(planScheduleList),1);
        log.info("redis search failure ···"+planScheduleList);
        return pageExample.getPages(planScheduleMapper.queryPlanResultByObjName(examineObjName),1);
    }

    /**
     * @param natureId
     * @return 根据计划性质分类
     */
    @Override
    @Transactional
    @MethodVerify
    public List<PlanResult> selectPlanResultByNatureId(String natureId) {
        Integer rt = ScheduleUtils.transferToInt(natureId);
        ScheduleUtils.enumerateCheck(rt,3);
        return planScheduleMapper.queryPlanResultByNatureId(rt);
    }

    /**
     * 根据检修对象类型，模糊查询计划调度管理数据
     * @param examineObjType
     * @return
     */
    @Override
    @Transactional
    @MethodVerify
    public List<PlanResult> selectPlanResultByObjType(String examineObjType) {
        List<PlanSchedule> planSchedules = getPlansByRedis();
        List<PlanSchedule> planScheduleList = matchDimPlanByObjType(planSchedules,examineObjType);
        if(planScheduleList.size() != 0)
            return pageExample.getPages(conformityPlanParam(planScheduleList),1);
        return pageExample.getPages(planScheduleMapper.queryPlanResultByObjType(examineObjType),1);
    }


    /**
     * 添加原始计划信息
     * @param plan
     * @return
     */
    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED)
    @MethodVerify
    public Integer addSave(PlanSchedule plan) {
        plan.setPlanId(MROUtils.nextId());
        plan.setIsDelete(1);
//        SaSession tokenSession = StpUtil.getTokenSession();
//        SysUser userInfo = (SysUser)tokenSession.get("userInfo");
//        plan.setCreateBy(userInfo.getLoginName());
//        plan.setUpdateBy(userInfo.getLoginName());
        //流程审批
        if(plan.getExaminePattern()==0)
            /* 计划的审批状态为未审批 */
            plan.setExamineState(0);
        else
            plan.setPlanState(2);
        /* 计划的状态为激活 */
        plan.setPlanState(0);
        /* 计划的创建时间、修改时间 */
        plan.setCreateTime(LocalDateTime.now());
        plan.setUpdateTime(LocalDateTime.now());
        /* 先缓存到redis，再持久化到DB */
        HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
        hashOperations.put(MROConstant.PLAN_MESSAGES,
                ScheduleUtils.transferStringByLong(plan.getPlanId()),plan);
        log.info("this is successful , redis save message --->"+MROConstant.PLAN_MESSAGES);
        return planScheduleMapper.insertPlan(plan);
    }

    /**
     * 修改原始计划信息
     * @param plan
     * @return
     */
    @Override
    @Transactional
    @MethodVerify
    public Integer editSave(PlanSchedule plan) {
        ScheduleUtils.planScheduleCheck(plan);
        /* 修改操作时间 */
        plan.setUpdateTime(LocalDateTime.now());
        Integer rt = planScheduleMapper.updatePlan(plan);
        if(rt == 1)
            setPlanToRedis(plan);
        return rt;
    }

    @Override
    public Integer editPlanSave(PlanResult planResult) {
        PlanSchedule plan =null;
        Integer natureId = matchPlanByNatureExplain(planResult.getPlanNatureExplain());
        Integer lifeCycleId = matchLifeCycleExplain(planResult.getLifeCycleExplain());
        Integer conditionId = matchExamineConditionExplain(planResult.getConditionExplain());
        Integer patternId = matchExaminePatternExplain(planResult.getPatternExplain());
        List<PlanSchedule> planScheduleList = planScheduleMapper.queryPlanById(planResult.getPlanId());
        if(planScheduleList.size() == 0 || planScheduleList.size() > 1)
            throw new MROException("edit planResult occur error",500);
        plan = planScheduleList.get(0);
        plan.setPlanNature(natureId);
        plan.setLifeCycle(lifeCycleId);
        plan.setExamineCondition(conditionId);
        plan.setExaminePattern(patternId);
        return planScheduleMapper.updatePlan(plan);
    }

    @Override
    @MethodVerify
    public Integer updateSaveByExamineState(String planId, String examineState) {
        Integer state = ScheduleUtils.transferToInt(examineState);
        ScheduleUtils.enumerateCheck(state,3);
        Integer rt = planScheduleMapper.updatePlanByExamineState(ScheduleUtils.transferToLong(planId), state);
        if(rt == 1)
        {
            PlanSchedule planByRedis = getPlanByRedis(ScheduleUtils.transferToLong(planId));
            if(planByRedis != null){
                planByRedis.setExamineState(ScheduleUtils.transferToInt(examineState));
                setPlanToRedis(planByRedis);
            }

        }
        return rt;
    }

    @Override
    @MethodVerify
    public Integer updateSaveByPlanState(String planId, String planState) {
        Integer state = ScheduleUtils.transferToInt(planState);
        ScheduleUtils.enumerateCheck(state,1);
        Integer rt = planScheduleMapper.updatePlanByPlanState(ScheduleUtils.transferToLong(planId),state);
        if(rt == 1)
        {
            PlanSchedule planByRedis = getPlanByRedis(ScheduleUtils.transferToLong(planId));
            if(planByRedis != null){
                planByRedis.setPlanState(ScheduleUtils.transferToInt(planState));
                setPlanToRedis(planByRedis);
            }
        }
        return rt;
    }

    /**
     * 删除原始计划信息
     * @param planId
     * @return
     */
    @Override
    @MethodVerify
    public Integer deleteSave(String planId)
    {
        /* 先删除DB,在删除redis中的缓存key */
        Integer rt = planScheduleMapper.removePlan(ScheduleUtils.transferToLong(planId));
        if(rt == 1)
            removePlanByPlanId(ScheduleUtils.transferToLong(planId));
        return rt;
    }

    @Override
    @MethodVerify
    public Integer deleteSaveByExamineState(String planId, String examineState) {
        Integer state = ScheduleUtils.transferToInt(examineState);
        ScheduleUtils.enumerateCheck(state,3);
        deleteSave(planId);
        return planScheduleMapper.deletePlanByExamineState(ScheduleUtils.transferToLong(planId),state);
    }

    @Override
    public Map planNature(String staffName, Integer planStateExplain) {
        Map<String,Object> map = new HashMap<>();
        for (PlanSchedule planSchedule : planScheduleMapper.queryPlanNature(staffName,planStateExplain)){
            String choiceExplain = null;
            if (planSchedule.getExamineChoice()==0) {
                choiceExplain = "零部件";
            }else if(planSchedule.getExamineChoice()==1){
                choiceExplain = "车辆对象";
            }
            map.put("planId",planSchedule.getPlanId());
            map.put("choiceExplain",choiceExplain);
            map.put("examineObjName",planSchedule.getExamineObjName());
        }
        return map;
    }

    public List<PlanResult> conformityPlanParam(List<PlanSchedule> plans){
        List<PlanResult> planResults = new Vector<>();
        Map<String, String> stringPlanNatureMap = planNatureParam();
        Map<String, String> stringPlanStateParamMap = productScheduleService.selectPlanStateParam();
        Map<String, String> stringLifeCycleMap = productScheduleService.selectLifeCycleParam();
        Map<String, String> stringExamineStateMap = productScheduleService.selectExamineStateParam();
        Map<String, String> stringExamineConditionMap = productScheduleService.selectExamineConditionParam();
        Map<String, String> stringExamineChoiceMap = productScheduleService.selectExamineChoiceParam();
        Map<String, String> stringExaminePatternMap = productScheduleService.selectExaminePatternParam();
        for (PlanSchedule pr:plans
             ) {
            PlanResult planResult = new PlanResult();
            planResult.setPlanId(pr.getPlanId());
            planResult.setExamineObjName(pr.getExamineObjName());
            planResult.setExamineObjType(pr.getExamineObjType());
            planResult.setPlanNatureExplain(stringPlanNatureMap.get(ScheduleUtils.transferStringByInteger(pr.getPlanNature())));
            planResult.setLifeCycleExplain(stringLifeCycleMap.get(ScheduleUtils.transferStringByInteger(pr.getLifeCycle())));
            planResult.setStateExplain(stringExamineStateMap.get(ScheduleUtils.transferStringByInteger(pr.getExamineState())));
            planResult.setChoiceExplain(stringExamineChoiceMap.get(ScheduleUtils.transferStringByInteger(pr.getExamineChoice())));
            planResult.setConditionExplain(stringExamineConditionMap.get(ScheduleUtils.transferStringByInteger(pr.getExamineCondition())));
            planResult.setChoiceExplain(stringExamineChoiceMap.get(ScheduleUtils.transferStringByInteger(pr.getExamineChoice())));
            planResult.setPatternExplain(stringExaminePatternMap.get(ScheduleUtils.transferStringByInteger(pr.getExaminePattern())));
            planResult.setPlanStateExplain(stringPlanStateParamMap.get(ScheduleUtils.transferStringByInteger(pr.getPlanState())));
            planResult.setCreateBy(pr.getCreateBy());
            planResult.setCreateTime(pr.getCreateTime());
            planResult.setUpdateBy(pr.getUpdateBy());
            planResult.setUpdateTime(pr.getUpdateTime());
            planResults.add(planResult);
        }
        System.out.println(planResults);
        return planResults;
    }
    public Map<String,String> planNatureParam(){
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        Map<String,String> entries = hashOperations.entries(MROConstant.SCHEDULE_PLAN_NATURE);
        return entries;
    }
    public Map<String,String> lifeCycleParam(){
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        Map<String,String> entries = hashOperations.entries(MROConstant.SCHEDULE_LIFE_CYCLE_STATE);
        return entries;
    }
    public Map<String,String> examineConditionParam(){
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        Map<String,String> entries = hashOperations.entries(MROConstant.SCHEDULE_EXAMINE_CONDITION_STATE);
        return entries;
    }
    public Map<String,String> examinePatternParam(){
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        Map<String,String> entries = hashOperations.entries(MROConstant.SCHEDULE_EXAMINE_PATTERN);
        return entries;
    }
    private List<PlanSchedule> getPlansByRedis(){
        HashOperations<String, String, PlanSchedule> hashOperations = redisTemplate.opsForHash();
        List<PlanSchedule> plans = hashOperations.values(MROConstant.PLAN_MESSAGES);
        return plans;
    }
    public PlanSchedule getPlanByRedis(Long planId){
        HashOperations<String, String, PlanSchedule> hashOperations = redisTemplate.opsForHash();
        return hashOperations.get(MROConstant.PLAN_MESSAGES,ScheduleUtils.transferStringByLong(planId));
    }
    private void setPlanToRedis(PlanSchedule plan){
        HashOperations<String, String, PlanSchedule> hashOperations = redisTemplate.opsForHash();
        hashOperations.put(MROConstant.PLAN_MESSAGES,ScheduleUtils.transferStringByLong(plan.getPlanId()),plan);
        log.info("this is successful , redis update message --->"+MROConstant.PLAN_MESSAGES);
    }
    private void removePlanByPlanId(Long planId){
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        hashOperations.delete(MROConstant.PLAN_MESSAGES,
                ScheduleUtils.transferStringByLong(planId));
        log.info("this is successful , redis remove message --->"+MROConstant.PLAN_MESSAGES);
    }

    private List<PlanSchedule> matchDimPlanId(List<PlanSchedule> planSchedules,Long planId) {
        return planSchedules.stream()
                .filter(ps -> ScheduleUtils.transferStringByLong(ps.getPlanId()).contains(ScheduleUtils.transferStringByLong(planId)))
                .collect(Collectors.toList());
    }
    private List<PlanSchedule> matchPlanId(List<PlanSchedule> planSchedules,Long planId) {
        return planSchedules.stream()
                .filter(ps -> ps.getPlanId()==planId)
                .collect(Collectors.toList());
    }
    private List<PlanSchedule> matchDimPlanByObjName(List<PlanSchedule> planSchedules,String examineObjName){
        return planSchedules.stream()
                .filter(ps -> ps.getExamineObjName().contains(examineObjName))
                .collect(Collectors.toList());
    }
    private List<PlanSchedule> matchDimPlanByObjType(List<PlanSchedule> planSchedules,String examineObjType){
        return planSchedules.stream()
                .filter(ps -> ps.getExamineObjType().contains(examineObjType))
                .collect(Collectors.toList());
    }
    private Integer matchPlanByNatureExplain(String natureName){
        Map<String, String> planNatureParam = planNatureParam();
        Set<Map.Entry<String, String>> entrySet = planNatureParam.entrySet();
        for (Map.Entry<String,String> item:entrySet
             ) {
            System.out.println("entrySet--"+entrySet);
            if(item.getValue().contains(natureName)){
                return ScheduleUtils.transferToInt(item.getKey());
            }
        }
        throw new MROException("nature name data not existed",500);
    }
    public Integer matchLifeCycleExplain(String lifeCycleName){
        Map<String, String> lifeCycleParam = lifeCycleParam();
        Set<Map.Entry<String, String>> entrySet = lifeCycleParam.entrySet();
        for (Map.Entry<String,String> item:entrySet
        ) {
            if(item.getValue().contains(lifeCycleName)){
                return ScheduleUtils.transferToInt(item.getKey());
            }
        }
        throw new MROException("lifeCycle name data not existed",500);
    }
    public Integer matchExamineConditionExplain(String examineConditionName){
        Map<String, String> examineConditionParam = examineConditionParam();
        Set<Map.Entry<String, String>> entrySet = examineConditionParam.entrySet();
        for (Map.Entry<String,String> item:entrySet
        ) {
            if(item.getValue().contains(examineConditionName)){
                return ScheduleUtils.transferToInt(item.getKey());
            }
        }
        throw new MROException("examineCondition name data not existed",500);
    }
    public Integer matchExaminePatternExplain(String examinePatternName){
        Map<String, String> examinePatternParam = examinePatternParam();
        Set<Map.Entry<String, String>> entrySet = examinePatternParam.entrySet();
        for (Map.Entry<String,String> item:entrySet
        ) {
            if(item.getValue().contains(examinePatternName)){
                return ScheduleUtils.transferToInt(item.getKey());
            }
        }
        throw new MROException("examinePattern name data not existed",500);
    }
}
